27 名称空间与作用域

852次阅读
没有评论

共计 1891 个字符,预计需要花费 5 分钟才能阅读完成。

引入

栈区 / 堆区

  • 栈区 : 存放的是变量名与变量值的内存地址 映射关系
  • 堆区 : 存放的是值 真正的位置

27 名称空间与作用域

一. 名称空间

1. 什么是名称空间

  • 存放名字与值绑定关系的地方
  • 名称空间是一个虚拟的概念, 栈区才真实存在

2. 为什么要有名称空间

  • 有了名称空间后就可以在内存的栈区存放相同的名字, 并且不会冲突

3. 名称空间是否有包含关系?

  • 名称空间本质之间是没有包含关系的, 并且相互独立

27 名称空间与作用域

二. 名称空间的分类(三类)

1. 内置名称空间

  • 存放内置的名字
  • 周期 : 在解释器启动时就产生,解释器关闭则失效
🎅例如我们常用的内置函数
print
len
input

2. 全局名称空间

  • 存放的是顶级的名字 (文件级别的名字)
  • 周期 : 在执行文件时生效,文件运行完毕或文件执行期间被删除则失效
x = 1      #全局名称空间
def foo(): #全局名称空间
    y = 2

🎅注意,"if" 下面的定义的变量名都是全局的
if 1 > 0        
    z = 3        #全局
    if 3 > 0: 
        p = 555  #全局

3. 局部名称空间

  • 存放函数内定义的名字
  • 周期 : 在函数调用时临时生效, 函数结束时则失效
def f()
    x = 222    #局部名称空间

f()   #函数调用结束失效

4. 名称空间的加载顺序

'内置名称空间'----->'全局名称空间'----->'局部名称空间'

5. 名称空间的查找优先级

'局部名称空间'----->'全局名称空间'----->'内置名称空间'

6. 名称空间的销毁顺序

'局部名称空间'----->'全局名称空间'----->'内置名称空间'

7. 名称空间总结与注意事项

  • 重要概念:名称空间的嵌套关系是在 函数定义阶段 (检测语法) 时确定的,与函数调用的位置无关,与函数 定义位置有关
  • 三种名称空间必须要有的是 : 内置 名称空间, 全局 名称空间

  • 查找优先级示例

🎅从 "f2" 局部开始找
x = 3
def f1():
    x = 2
    def f2():
        x =1
        print(x)
    f2()
f1()  # 1

🎅将 "f2" 局部的删除, 就往上一层找, 找到 "f1"
x = 3
def f1():
    x = 2
    def f2():
        print(x)
    f2()
f1()  # 2

🎅再将 "f1" 里面的删除, 于是找到了全局
x = 3
def f1():
    def f2():
        print(x)
    f2()
f1()  # 3
  • 函数的嵌套定义示例
🎅在定义 "f2" 的之后, 有定义了同一级别的 "len", 所以当打开函数 "f2" 运行的时候, 本着优先级查找就先找到了 "222"
len = 111
def f1():
    def f2():
        print(len) # 222
    len = 222
    f2()
f1()  # 222

三. 作用域

1. 什么是作用域

  • 作用域就是根据名称空间的范围和特点进行了归类
  • 查看作用域 : globals(), locals()

2. 全局作用域

  • 包含 : 内置名称空间, 全局名称空间
  • 特点 : 全局存活, 全局有效

3. 局部作用域

  • 包含 : 局部名称空间
  • 特点 : 临时存活, 局部有效

4.L E G B

  • LEGB 代表名字查找顺序 : L--->E--->G--->B
  • locals : 是函数内的名字空间, 包括局部变量和形参
  • enclosing : 外部嵌套的名称空间(闭包中常见面)
  • globals : 全局变量, 函数定义所在模块的名字空间
  • builtins : 内置模块的名字空间

四.global 与 nonlocal 关键字

1.global 关键字

  • 使用方法 : global x 声明这个 x 是全局变量
  • 针对的是不可变类型的值
🎅在全局空间定义一个变量 "x", 函数 "foo", 在函数内部修改 "x" 的值
x = 111
def foo():
    x = 222

foo()
print(x)   #111
#发现并无软用

🎅使用 "global" 关键字之后
x = 111
def foo():
    global x  # 声明下面的 "x" 属于全局
    x = 222

foo()
print(x)  #222
#发现成功了

2.nonlocal 关键字

  • 使用方法 : nonlocal x , 声明外层函数的局部变量
  • 修改该函数外层函数包含的变量名对应的值, 也是针对不可变类型
  • 注意 : 只能在局部名称空间中查找, 先从外部嵌套的函数找, 没找到再往上找, 如果都没找到则报错
🎅不做任何处理, 此函数应该是打印 "f2" 函数下的 "x = 333"
x = 111
def f1():
    x = 222
    def f2():
        x = 333
        def f3():
            x = 444
        f3()
        print(x)  #333
    f2()
f1()  # 333

🎅使用 "nonlocal" 关键字
x = 111
def f1():
    x = 222
    def f2():
        x = 333
        def f3():
            nonlocal x  #将下面的 "x = 444" 变成了上一层的 "x" 的值
            x = 444
        f3()
        print(x) 
    f2()
f1()  # 444

🎅如果外层函数都没有 "x" 这个值, 报错
x = 111  #并不会去全局修改
def f1():
    def f2():
        def f3():
            nonlocal x
            x = 444
        f3()
        print(x)
    f2()
f1()  #报错
正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计1891字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)